﻿/*
 * Copyright (C) 2013 David Neal Parsons
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TripleAMapGenerator
{
    class GameMap
    {
        // Basic
        private string path;
        private string rootPath;
        public Random Rand;
        public string MapFolder;
        public bool FFA; // Free for all
        public string MapName;
        public int RandomSeed;
        public int DiceSides;
        public bool WW2V2;

        // Players
        public int NumberOfPlayers;
        public int NumberOfTeams;
        public int CapitalSize;
        public int CapitalDistance;
        public int ResourcesGiven;
        public int BoostPerPlayer;
        public int Bid;
        public bool OwnCapitals;
        public bool OwnPercentVC;
        public int OwnPercentVCAmount;
        public bool CTF; // Capture the flag
        public bool UseTriggers;
        public string CapitalLocations;
        public string VCLocations;
        public int VCCount;
        public int NumberOfVCToWin;
        public string FlagLocation;

        // Territories
        public int NumberOfColumns;
        public int NumberOfRows;
        public int PercentWater;
        public int PercentImpassable;
        public int PercentForest;
        public int PercentMtn;
        public int PercentDesert;
        public int PercentHill;
        public int PercentMarsh;
        public int PercentCity;
        public int PercentNeutralExtras;
        public int PercentVC;

        // Units
        public bool UseAdditional;

        // Tech
        public bool UseTech;
        public int PercentTech;
        public bool InitialJet;
        public bool InitialSub;
        public bool InitialAir;
        public bool InitialDestroyer;
        public bool InitialBomber;
        public bool InitialIT;

        public List<Player> Players;
        public List<Territory> Territories;
        public List<Territory> AvailableTerritories;
        public List<UsedTerritory> UsedTerritories;
        public List<Connection> Connections;
        public List<Unit> Units;

        public List<string> ErrorList;

        public GameMap()
        {
            ErrorList = new List<string>();
            Players = new List<Player>();
            Territories = new List<Territory>();
            UsedTerritories = new List<UsedTerritory>();
            Connections = new List<Connection>();
            Units = new List<Unit>();
        }

        public void MapInitialize()
        {
            Rand = new Random(RandomSeed);
            Rand.Next();

            TerritoryInitialize();
            ConnectionInitialize();
            PlayerInitialize();
            UnitInitialize();
            TerritoryAttachmentInitialize();
        }

        // Territories
        private void TerritoryInitialize()
        {
            Territories.Clear();
            for (int i = 0; i < NumberOfColumns; i++)
            {
                for (int j = 0; j < NumberOfRows; j++)
                {
                    Territory t = new Territory();
                    t.Name = GetTerritoryName(i + 1, j + 1);

                    Territories.Add(t);
                }
            }
        }

        // Connections
        private void ConnectionInitialize()
        {
            Connections.Clear();
            for (int row = 0; row < NumberOfRows - 1; row++)
            {
                for (int col = 0; col < NumberOfColumns; col++)
                {
                    Connection c1 = new Connection();
                    c1.t1 = Territories[(col * NumberOfRows) + row];
                    c1.t2 = Territories[((col * NumberOfRows) + row) + 1];
                    Connections.Add(c1);
                }
            }

            for (int row = 0; row < NumberOfRows; row++)
            {
                for (int col = 0; col < NumberOfColumns - 1; col++)
                {
                    Connection c1 = new Connection();
                    c1.t1 = Territories[(col * NumberOfRows) + row];
                    c1.t2 = Territories[((col * NumberOfRows) + NumberOfRows + row)];
                    Connections.Add(c1);
                }
            }

            for (int row = 0; row < NumberOfRows - 1; row++)
            {
                for (int col = 0; col < NumberOfColumns - 1; col++)
                {
                    if (col % 2 == 0) // Odd columns, e.g., 0101
                    {
                        if (row != 0)
                        {
                            Connection c1 = new Connection();
                            c1.t1 = Territories[(col * NumberOfRows) + row];
                            c1.t2 = Territories[((col * NumberOfRows) + NumberOfRows + row) - 1];
                            Connections.Add(c1);
                        }
                    }
                    else // Even columns, e.g., 0201
                    {
                        Connection c1 = new Connection();
                        c1.t1 = Territories[(col * NumberOfRows) + row];
                        c1.t2 = Territories[((col * NumberOfRows) + NumberOfRows + row) + 1];
                        Connections.Add(c1);
                    }
                }
            }

            for (int col = 0; col < NumberOfColumns - 1; col++)
            {
                if (col % 2 == 0) // Odd columns, e.g., 0101
                {
                    Connection c1 = new Connection();
                    c1.t1 = Territories[(col * NumberOfRows) + NumberOfRows - 1];
                    c1.t2 = Territories[(((col + 1) * NumberOfRows) + NumberOfRows) - 2];
                    Connections.Add(c1);
                }
            }
        }

        // Players
        private void PlayerInitialize()
        {
            Players.Clear();
            int idx = MapFolder.LastIndexOf(System.IO.Path.DirectorySeparatorChar) + 1;
            int cnt = MapFolder.Length - MapFolder.LastIndexOf(System.IO.Path.DirectorySeparatorChar) - 1;
            rootPath = MapFolder.Remove(idx, cnt);
            path = rootPath + "units";

            // Get the Player names from the map units folder
            // Default alliance for each player is itself (FFA)
            foreach (string folder in System.IO.Directory.GetDirectories(path))
            {
                Player p = new Player();
                p.Name = System.IO.Path.GetFileName(folder);
                p.Optional = false;
                p.Alliance = System.IO.Path.GetFileName(folder);
                Players.Add(p);
            }

            // Remove "Neutral" as a player choice
            Player result = Players.Find(
                delegate(Player pn)
                {
                    return pn.Name == "Neutral";
                }
            );
            Players.Remove(result);

            // Adjust to the number of players specified in the UI
            int playerCount = Players.Count;
            if (playerCount > NumberOfPlayers)
            {
                Players.RemoveRange(NumberOfPlayers, playerCount - NumberOfPlayers);
            }

            // Give initial resources
            int amount = ResourcesGiven;
            foreach (Player p in Players)
            {
                p.InitialResources = amount;
                amount += BoostPerPlayer;
            }

            // Adjust player alliances for teams
            if (!FFA)
            {
                int playersPerTeam = NumberOfPlayers / NumberOfTeams;
                for (int i = 0; i < NumberOfTeams; i++)
                {
                    for (int j = 0; j < playersPerTeam; j++)
                    {
                        Players[(i * playersPerTeam) + j].Alliance = "Team" + (i + 1).ToString("D2");
                    }
                }
            }
        }

        // Units
        private void UnitInitialize()
        {
            Units.Clear();

            // Assign properties for each unit type

            // Land

            // infantry
            Unit u = new Unit();
            u.Name = "infantry";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 2;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            UnitOption uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "transportCost";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isInfantry";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "artillerySupportable";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isAirTransportable";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            Units.Add(u);

            // marine
            u = new Unit();
            u.Name = "marine";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 3;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "transportCost";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isInfantry";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isMarine";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "artillerySupportable";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isAirTransportable";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            Units.Add(u);

            // elite
            u = new Unit();
            u.Name = "elite";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 4;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "transportCost";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isInfantry";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "artillerySupportable";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isAirTransportable";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            Units.Add(u);

            // scout
            u = new Unit();
            u.Name = "scout";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 3;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "transportCost";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "canBlitz";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            Units.Add(u);

            // artillery
            u = new Unit();
            u.Name = "artillery";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 4;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "transportCost";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "artillery";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isAirTransportable";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            Units.Add(u);

            // halftrack
            u = new Unit();
            u.Name = "halftrack";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 6;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "transportCost";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "artillery";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isLandTransport";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "canBlitz";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            Units.Add(u);

            // armour
            u = new Unit();
            u.Name = "armour";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 5;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "transportCost";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isLandTransport";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "canBlitz";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            Units.Add(u);

            // armourBig
            u = new Unit();
            u.Name = "armourBig";
            u.IsAdditional = true;
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 9;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "transportCost";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isLandTransport";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "canBlitz";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isTwoHit";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            Units.Add(u);

            // Air

            // fighter
            u = new Unit();
            u.Name = "fighter";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 10;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 4;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 4;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isAir";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "carrierCost";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "canScramble";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "maxScrambleDistance";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "canIntercept";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "canEscort";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "airDefense";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "airAttack";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            Units.Add(u);

            // bomber
            u = new Unit();
            u.Name = "bomber";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 14;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 4;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 6;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isAir";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isStrategicBomber";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "airAttack";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            Units.Add(u);

            // airTransport
            u = new Unit();
            u.Name = "airTransport";
            u.IsAdditional = true;
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 10;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 4;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isAir";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isAirTransport";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "transportCapacity";
            uo.Value = 6;
            u.attachment.options.Add(uo);
            Units.Add(u);

            // Sea

            // transport
            u = new Unit();
            u.Name = "transport";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 8;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isSea";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "transportCapacity";
            uo.Value = 5;
            u.attachment.options.Add(uo);
            Units.Add(u);

            // carrier
            u = new Unit();
            u.Name = "carrier";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 15;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isSea";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "carrierCapacity";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "blockade";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            Units.Add(u);

            // superCarrier
            u = new Unit();
            u.Name = "superCarrier";
            u.IsAdditional = true;
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 22;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isSea";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isTwoHit";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isCombatTransport";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "carrierCapacity";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "transportCapacity";
            uo.Value = 5;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "blockade";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            Units.Add(u);

            // destroyer
            u = new Unit();
            u.Name = "destroyer";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 9;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isSea";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isDestroyer";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "blockade";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            Units.Add(u);

            // cruiser
            u = new Unit();
            u.Name = "cruiser";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 13;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isSea";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "canBombard";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "bombard";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "blockade";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            Units.Add(u);

            // battlecruiser
            u = new Unit();
            u.Name = "battlecruiser";
            u.IsAdditional = true;
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 17;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isSea";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "canBombard";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "bombard";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "blockade";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isTwoHit";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            Units.Add(u);

            // battleship
            u = new Unit();
            u.Name = "battleship";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 21;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 4;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 4;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isSea";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isTwoHit";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "canBombard";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "bombard";
            uo.Value = 4;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "blockade";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            Units.Add(u);

            // submarine
            u = new Unit();
            u.Name = "submarine";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 7;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isSea";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isSub";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "blockade";
            uo.Value = 2;
            u.attachment.options.Add(uo);
            Units.Add(u);

            // Misc

            // bunker
            u = new Unit();
            u.Name = "bunker";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 5;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 4;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isTwoHit";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            Units.Add(u);

            // factory
            u = new Unit();
            u.Name = "factory";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 15;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isFactory";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            Units.Add(u);

            // airfield
            u = new Unit();
            u.Name = "airfield";
            u.IsAdditional = true;
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 12;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isAirBase";
            uo.Value = "true";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "givesMovement";
            uo.Value = "1:fighter";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "givesMovement";
            uo.Value = "1:bomber";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "givesMovement";
            uo.Value = "1:airTransport";
            u.attachment.options.Add(uo);
            Units.Add(u);

            // harbour
            u = new Unit();
            u.Name = "harbour";
            u.IsAdditional = true;
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 12;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "givesMovement";
            uo.Value = "1:submarine";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "givesMovement";
            uo.Value = "1:destroyer";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "givesMovement";
            uo.Value = "1:cruiser";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "givesMovement";
            uo.Value = "1:carrier";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "givesMovement";
            uo.Value = "1:battleship";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "givesMovement";
            uo.Value = "1:superCarrier";
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "givesMovement";
            uo.Value = "1:battlecruiser";
            u.attachment.options.Add(uo);
            Units.Add(u);

            // aaGun
            u = new Unit();
            u.Name = "aaGun";
            u.cost = new Cost();
            u.cost.ResourceType = "PUs";
            u.cost.cost = 6;
            u.cost.result = new Result();
            u.cost.result.ResourceOrUnitName = u.Name;
            u.cost.result.BuyQuantity = 1;

            u.attachment = new UnitAttachment();
            uo = new UnitOption();
            uo.Name = "attack";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "defense";
            uo.Value = 0;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "movement";
            uo.Value = 1;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "transportCost";
            uo.Value = 3;
            u.attachment.options.Add(uo);
            uo = new UnitOption();
            uo.Name = "isAA";
            uo.Value = "True";
            u.attachment.options.Add(uo);
            Units.Add(u);

            // Industrial Production tech is loosely based on house rules.
            // At 15% IT cost reduction:
            // Units with original cost of 6 or less get no reduction.
            // Units with original cost of 7 to 13 get a cost reduction of 1.
            // Unit costs between 14 and 19 are reduced by 2.
            // Units costing 20+ are reduced by 3.
            foreach (Unit un in Units)
            {
                un.techCost = new Cost();
                un.techCost.ResourceType = "PUs";
                un.techCost.result = new Result();
                un.techCost.result.ResourceOrUnitName = un.Name;
                un.techCost.result.BuyQuantity = 1;

                int reduction = (un.cost.cost * PercentTech) / 100;
                un.techCost.cost = un.cost.cost - reduction;
                if (un.techCost.cost < 1)
                {
                    un.techCost.cost = 1;
                }
            }
        }

        // Territory Attachments
        private void TerritoryAttachmentInitialize()
        {
            ErrorList.Clear();
            int iterationCount = 10000;
            VCCount = 0;

            // Default one PU and one infantry per territory
            foreach (Territory t in Territories)
            {
                Unit ur = Units.Find(
                    delegate(Unit ui)
                    {
                        return ui.Name == "infantry";
                    }
                );

                t.Units.Add(ur);
                t.placeQty.Add(1);
                t.Production = 1;
            }

            // Capture the flag
            if (CTF)
            {
                int flagCol = NumberOfColumns / 2;
                int flagRow = NumberOfRows / 2;
                FlagLocation = GetTerritoryName(flagCol, flagRow);
                UsedTerritory utFlag = new UsedTerritory();
                utFlag.t1.Name = FlagLocation;
                UsedTerritories.Add(utFlag);
                VCLocations = FlagLocation;
                VCCount++;

                int ndx = Territories.FindIndex(
                    delegate(Territory tr)
                    {
                        return tr.Name == FlagLocation;
                    }
                );

                Territories[ndx].Production = 20;
                Territories[ndx].IsVictoryCity = true;

                Territories[ndx].Units.Clear();
                Territories[ndx].placeQty.Clear();
                Unit ur = Units.Find(
                    delegate(Unit ui)
                    {
                        return ui.Name == "infantry";
                    }
                );
                Territories[ndx].Units.Add(ur);
                Territories[ndx].placeQty.Add(5);

                ur = Units.Find(
                    delegate(Unit ui)
                    {
                        return ui.Name == "artillery";
                    }
                );
                Territories[ndx].Units.Add(ur);
                Territories[ndx].placeQty.Add(5);

                ur = Units.Find(
                    delegate(Unit ui)
                    {
                        return ui.Name == "armour";
                    }
                );
                Territories[ndx].Units.Add(ur);
                Territories[ndx].placeQty.Add(3);

                ur = Units.Find(
                    delegate(Unit ui)
                    {
                        return ui.Name == "bunker";
                    }
                );
                Territories[ndx].Units.Add(ur);
                Territories[ndx].placeQty.Add(2);
            }

            // Capitals
            int iterations = iterationCount;
            string capitalDelimiter = "";
            string vcDelimiter = CTF ? ":" : "";
            foreach (Player p in Players)
            {
                bool territoryFound = true;
                int ndx = -1;
                while (territoryFound)
                {
                    int col = Rand.Next(2, NumberOfColumns);
                    int row = Rand.Next(2, NumberOfRows);

                    // Check to see if the territory is used
                    UsedTerritory utr = UsedTerritories.Find(
                        delegate(UsedTerritory utc)
                        {
                            return utc.t1.Name == GetTerritoryName(col, row);
                        }
                    );

                    // If the territory is available
                    if (utr == null)
                    {
                        // Check to see if it is too close to another player capital
                        bool tooClose = false;
                        foreach (UsedTerritory t in UsedTerritories)
                        {
                            int a = col - Convert.ToInt32(t.t1.Name.Substring(1,2));
                            int b = row - Convert.ToInt32(t.t1.Name.Substring(4, 2));
                            int distance = Convert.ToInt32(Math.Ceiling(Math.Sqrt(((a * a) + (b * b)))));
                            if (distance < CapitalDistance)
                            {
                                tooClose = true;
                                break;
                            }
                        }

                        // If not too close
                        // Add the territory to the UsedTerritories list,
                        // and make it a capital for that player.
                        // All capitals are also VC.
                        if (!tooClose)
                        {
                            UsedTerritory ut = new UsedTerritory();
                            ut.t1.Name = GetTerritoryName(col, row);
                            UsedTerritories.Add(ut);
                            CapitalLocations += capitalDelimiter + ut.t1.Name;
                            VCLocations += vcDelimiter + ut.t1.Name;
                            capitalDelimiter = ":";
                            vcDelimiter = ":";
                            VCCount++;

                            ndx = Territories.FindIndex(
                                delegate(Territory tr)
                                {
                                    return tr.Name == GetTerritoryName(col, row);
                                }
                            );

                            Territories[ndx].Production = 10;
                            Territories[ndx].IsCapitol = true;
                            Territories[ndx].IsVictoryCity = true;
                            Territories[ndx].Owner = p;

                            Territories[ndx].Units.Clear();
                            Territories[ndx].placeQty.Clear();
                            Unit ur = Units.Find(
                                delegate(Unit ui)
                                {
                                    return ui.Name == "factory";
                                }
                            );
                            Territories[ndx].Units.Add(ur);
                            Territories[ndx].placeQty.Add(1);

                            ur = Units.Find(
                                delegate(Unit ui)
                                {
                                    return ui.Name == "aaGun";
                                }
                            );
                            Territories[ndx].Units.Add(ur);
                            Territories[ndx].placeQty.Add(1);

                            // Add surrounding area to UsedTerritories
                            // Designate as owner depending on CapitalSize
                            int capSize = CapitalSize;
                            foreach (Connection c in Connections)
                            {
                                if (c.t1.Name == Territories[ndx].Name || c.t2.Name == Territories[ndx].Name)
                                {
                                    UsedTerritory utc = new UsedTerritory();

                                    if (c.t1.Name == Territories[ndx].Name)
                                    {
                                        utc.t1.Name = c.t2.Name;
                                        if (capSize-- > 1)
                                        {
                                            int newNdx = Territories.FindIndex(
                                                delegate(Territory tr)
                                                {
                                                    return tr.Name == c.t2.Name;
                                                }
                                            );
                                            Territories[newNdx].Owner = p;
                                            Territories[newNdx].Units.Clear();
                                        }
                                    }
                                    else
                                    {
                                        utc.t1.Name = c.t1.Name;
                                        if (capSize-- > 1)
                                        {
                                            int newNdx = Territories.FindIndex(
                                                delegate(Territory tr)
                                                {
                                                    return tr.Name == c.t1.Name;
                                                }
                                            );
                                            Territories[newNdx].Owner = p;
                                            Territories[newNdx].Units.Clear();
                                        }
                                    }

                                    UsedTerritories.Add(utc);
                                }
                            }

                            territoryFound = false;
                        }
                    }
                    else
                    {
                        territoryFound = true;
                    }
                    if (iterations-- < 1)
                    {
                        break;
                    };
                }
                if (iterations < 1)
                {
                    ErrorList.Add("Cannot place Capital.");
                    break;
                };
            }

            // Water
            int mapSize = NumberOfColumns * NumberOfRows;
            int waterSize = mapSize * PercentWater / 100;

            iterations = iterationCount;
            for (int i = 0; i < waterSize; i++)
            {
                bool duplicateFound = true;
                while (duplicateFound)
                {
                    int col = Rand.Next(1, NumberOfColumns + 1);
                    int row = Rand.Next(1, NumberOfRows + 1);

                    UsedTerritory utr = UsedTerritories.Find(
                        delegate(UsedTerritory utc)
                        {
                            return utc.t1.Name == GetTerritoryName(col, row);
                        }
                    );

                    if (utr == null)
                    {
                        UsedTerritory ut = new UsedTerritory();
                        ut.t1.Name = GetTerritoryName(col, row);
                        UsedTerritories.Add(ut);

                        int ndx = Territories.FindIndex(
                            delegate(Territory tr)
                            {
                                return tr.Name == GetTerritoryName(col, row);
                            }
                        );

                        Territories[ndx].Production = 0;
                        Territories[ndx].IsWater = true;

                        Territories[ndx].Units.Clear();
                        duplicateFound = false;
                    }
                    else
                    {
                        duplicateFound = true;
                    }
                    if (iterations-- < 1)
                    {
                        break;
                    };
                }
                if (iterations < 1)
                {
                    ErrorList.Add("Map is too filled with water.");
                    break;
                }
            }

            // Impassable
            int impassSize = mapSize * PercentImpassable / 100;

            iterations = iterationCount;
            for (int i = 0; i < impassSize; i++)
            {
                bool duplicateFound = true;
                while (duplicateFound)
                {
                    int col = Rand.Next(1, NumberOfColumns + 1);
                    int row = Rand.Next(1, NumberOfRows + 1);

                    UsedTerritory utr = UsedTerritories.Find(
                        delegate(UsedTerritory utc)
                        {
                            return utc.t1.Name == GetTerritoryName(col, row);
                        }
                    );

                    if (utr == null)
                    {
                        UsedTerritory ut = new UsedTerritory();
                        ut.t1.Name = GetTerritoryName(col, row);
                        UsedTerritories.Add(ut);

                        int ndx = Territories.FindIndex(
                            delegate(Territory tr)
                            {
                                return tr.Name == GetTerritoryName(col, row);
                            }
                        );

                        Territories[ndx].Production = 0;
                        Territories[ndx].IsImpassable = true;

                        Territories[ndx].Units.Clear();
                        duplicateFound = false;
                    }
                    else
                    {
                        duplicateFound = true;
                    }
                    if (iterations-- < 1)
                    {
                        break;
                    };
                }
                if (iterations < 1)
                {
                    ErrorList.Add("Map is too filled with impassables.");
                    break;
                }
            }

            AddTerrain();

            // Extra Production
            Unit uInf = Units.Find(
                delegate(Unit ui)
                {
                    return ui.Name == "infantry";
                }
            );

            Unit uArt = Units.Find(
                delegate(Unit ui)
                {
                    return ui.Name == "artillery";
                }
            );
            
            Unit uBunker = Units.Find(
                delegate(Unit ui)
                {
                    return ui.Name == "bunker";
                }
            );

            Unit uElite = Units.Find(
                delegate(Unit ui)
                {
                    return ui.Name == "elite";
                }
            );

            // Percent Extras only applies to remaining neutral territories
            // after subtracting capital, water, and impassable territories
            if (mapSize - UsedTerritories.Count > 10)
            {
                iterations = iterationCount;
                int extraSize = (mapSize - UsedTerritories.Count) * PercentNeutralExtras / 100;
                for (int i = 0; i < extraSize; i++)
                {
                    bool duplicateFound = true;
                    while (duplicateFound)
                    {
                        int col = Rand.Next(1, NumberOfColumns + 1);
                        int row = Rand.Next(1, NumberOfRows + 1);

                        UsedTerritory utr = UsedTerritories.Find(
                            delegate(UsedTerritory utc)
                            {
                                return utc.t1.Name == GetTerritoryName(col, row);
                            }
                        );

                        if (utr == null)
                        {
                            UsedTerritory ut = new UsedTerritory();
                            ut.t1.Name = GetTerritoryName(col, row);
                            UsedTerritories.Add(ut);

                            int ndx = Territories.FindIndex(
                                delegate(Territory tr)
                                {
                                    return tr.Name == GetTerritoryName(col, row);
                                }
                            );

                            // 10% chance of production 4
                            // 20% chance of production 3
                            // 70% chance of production 2
                            int randProd = Rand.Next(1, 101);
                            if (randProd < 11)
                            {
                                Territories[ndx].Production = 4;
                                Territories[ndx].Units.Clear();
                                Territories[ndx].placeQty.Clear();
                                Territories[ndx].Units.Add(uInf);
                                Territories[ndx].placeQty.Add(1);
                                Territories[ndx].Units.Add(uElite);
                                Territories[ndx].placeQty.Add(1);
                                Territories[ndx].Units.Add(uArt);
                                Territories[ndx].placeQty.Add(1);
                                Territories[ndx].Units.Add(uBunker);
                                Territories[ndx].placeQty.Add(1);
                            }
                            else if (randProd < 31)
                            {
                                Territories[ndx].Production = 3;
                                Territories[ndx].Units.Clear();
                                Territories[ndx].placeQty.Clear();
                                Territories[ndx].Units.Add(uInf);
                                Territories[ndx].placeQty.Add(1);
                                Territories[ndx].Units.Add(uElite);
                                Territories[ndx].placeQty.Add(1);
                                Territories[ndx].Units.Add(uArt);
                                Territories[ndx].placeQty.Add(1);
                            }
                            else
                            {
                                Territories[ndx].Production = 2;
                                Territories[ndx].Units.Clear();
                                Territories[ndx].placeQty.Clear();
                                Territories[ndx].Units.Add(uInf);
                                Territories[ndx].placeQty.Add(1);
                                Territories[ndx].Units.Add(uArt);
                                Territories[ndx].placeQty.Add(1);
                            }

                            duplicateFound = false;
                        }
                        else
                        {
                            duplicateFound = true;
                        }
                        if (iterations-- < 1)
                        {
                            break;
                        };
                    }
                    if (iterations < 1)
                    {
                        ErrorList.Add("Cannot add extra Neutral production to terrain.");
                        break;
                    }
                }
            }

            // Victory Cities
            Unit uArmour = Units.Find(
                delegate(Unit ui)
                {
                    return ui.Name == "armour";
                }
            );

            // Percent VC only applies to remaining neutral territories
            // after subtracting capital, water, impassable, and extra production territories
            if (mapSize - UsedTerritories.Count > 5)
            {
                iterations = iterationCount;
                int vcSize = (mapSize - UsedTerritories.Count) * PercentVC / 100;
                for (int i = 0; i < vcSize; i++)
                {
                    bool duplicateFound = true;
                    while (duplicateFound)
                    {
                        int col = Rand.Next(1, NumberOfColumns + 1);
                        int row = Rand.Next(1, NumberOfRows + 1);

                        UsedTerritory utr = UsedTerritories.Find(
                            delegate(UsedTerritory utc)
                            {
                                return utc.t1.Name == GetTerritoryName(col, row);
                            }
                        );

                        if (utr == null)
                        {
                            UsedTerritory ut = new UsedTerritory();
                            ut.t1.Name = GetTerritoryName(col, row);
                            UsedTerritories.Add(ut);
                            VCLocations += vcDelimiter + ut.t1.Name;
                            vcDelimiter = ":";
                            VCCount++;
                            

                            int ndx = Territories.FindIndex(
                                delegate(Territory tr)
                                {
                                    return tr.Name == GetTerritoryName(col, row);
                                }
                            );

                            Territories[ndx].IsVictoryCity = true;
                            Territories[ndx].Production = 5;
                            Territories[ndx].Units.Clear();
                            Territories[ndx].placeQty.Clear();
                            Territories[ndx].Units.Add(uInf);
                            Territories[ndx].placeQty.Add(1);
                            Territories[ndx].Units.Add(uElite);
                            Territories[ndx].placeQty.Add(1);
                            Territories[ndx].Units.Add(uArt);
                            Territories[ndx].placeQty.Add(1);
                            Territories[ndx].Units.Add(uBunker);
                            Territories[ndx].placeQty.Add(1);
                            Territories[ndx].Units.Add(uArmour);
                            Territories[ndx].placeQty.Add(1);

                            duplicateFound = false;
                        }
                        else
                        {
                            duplicateFound = true;
                        }
                        if (iterations-- < 1)
                        {
                            break;
                        };
                    }
                    if (iterations < 1)
                    {
                        ErrorList.Add("Cannot add Victory Cities to terrain.");
                        break;
                    }
                }
            }
            NumberOfVCToWin = (VCCount * OwnPercentVCAmount) / 100;
            if (NumberOfVCToWin < 1)
            {
                NumberOfVCToWin = 1;
            }
        }

        private void AddTerrain()
        {
            // Calculate neutral territories
            AvailableTerritories = new List<Territory>();
            AvailableTerritories.AddRange(Territories);

            foreach (UsedTerritory ut in UsedTerritories)
            {
                Territory tr = AvailableTerritories.Find(
                    delegate(Territory t)
                    {
                        return t.Name == ut.t1.Name;
                    }
                );

                if (tr != null)
                {
                    AvailableTerritories.Remove(tr);
                }
            }

            // Forest
            int availableCount = AvailableTerritories.Count;
            int forestSize = AvailableTerritories.Count * PercentForest / 100;

            for (int i = 0; i < forestSize; i++)
            {
                int ndx = Rand.Next(0, availableCount);
                Territory tr = Territories.Find(
                    delegate(Territory t)
                    {
                        return t.Name == AvailableTerritories[ndx].Name;
                    }
                );

                if (tr != null)
                {
                    AvailableTerritories.Remove(AvailableTerritories[ndx]);
                    availableCount--;
                    tr.TerritoryEffect = "forest";
                }
            }

            // Mountain
            availableCount = AvailableTerritories.Count;
            int mntSize = AvailableTerritories.Count * PercentMtn / 100;

            for (int i = 0; i < mntSize; i++)
            {
                int ndx = Rand.Next(0, availableCount);
                Territory tr = Territories.Find(
                    delegate(Territory t)
                    {
                        return t.Name == AvailableTerritories[ndx].Name;
                    }
                );

                if (tr != null)
                {
                    AvailableTerritories.Remove(AvailableTerritories[ndx]);
                    availableCount--;
                    tr.TerritoryEffect = "mountain";
                }
            }

            // Desert
            availableCount = AvailableTerritories.Count;
            int desertSize = AvailableTerritories.Count * PercentDesert / 100;

            for (int i = 0; i < desertSize; i++)
            {
                int ndx = Rand.Next(0, availableCount);
                Territory tr = Territories.Find(
                    delegate(Territory t)
                    {
                        return t.Name == AvailableTerritories[ndx].Name;
                    }
                );

                if (tr != null)
                {
                    AvailableTerritories.Remove(AvailableTerritories[ndx]);
                    availableCount--;
                    tr.TerritoryEffect = "desert";
                }
            }

            // Hill
            availableCount = AvailableTerritories.Count;
            int hillSize = AvailableTerritories.Count * PercentHill / 100;

            for (int i = 0; i < hillSize; i++)
            {
                int ndx = Rand.Next(0, availableCount);
                Territory tr = Territories.Find(
                    delegate(Territory t)
                    {
                        return t.Name == AvailableTerritories[ndx].Name;
                    }
                );

                if (tr != null)
                {
                    AvailableTerritories.Remove(AvailableTerritories[ndx]);
                    availableCount--;
                    tr.TerritoryEffect = "hills";
                }
            }

            // Marsh
            availableCount = AvailableTerritories.Count;
            int marshSize = AvailableTerritories.Count * PercentMarsh / 100;

            for (int i = 0; i < marshSize; i++)
            {
                int ndx = Rand.Next(0, availableCount);
                Territory tr = Territories.Find(
                    delegate(Territory t)
                    {
                        return t.Name == AvailableTerritories[ndx].Name;
                    }
                );

                if (tr != null)
                {
                    AvailableTerritories.Remove(AvailableTerritories[ndx]);
                    availableCount--;
                    tr.TerritoryEffect = "marsh";
                }
            }

            // City
            availableCount = AvailableTerritories.Count;
            int citySize = AvailableTerritories.Count * PercentCity / 100;

            for (int i = 0; i < citySize; i++)
            {
                int ndx = Rand.Next(0, availableCount);
                Territory tr = Territories.Find(
                    delegate(Territory t)
                    {
                        return t.Name == AvailableTerritories[ndx].Name;
                    }
                );

                if (tr != null)
                {
                    AvailableTerritories.Remove(AvailableTerritories[ndx]);
                    availableCount--;
                    tr.TerritoryEffect = "city";
                }
            }
        }

        public string GetTerritoryName(int col, int row)
        {
            return "c" + col.ToString("D2") + "r" + row.ToString("D2");
        }
    }
}
